package com.example.component;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.DialogInterface;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ListAdapter;

public class AlertDialogFragment extends DialogFragment {
    private static final String TAG = AlertDialogFragment.class.getSimpleName();
    private AlertParams mParams;

    private int mRequestFocusId;
    private OnCancelListener mOnCancelListener;
    private OnKeyListener mOnKeyListener;
    private OnClickListener mOnClickListener;
    private OnMultiChoiceClickListener mOnMultiChoiceClickListener;
    private OnClickListener mPositiveButtonListener;
    private OnClickListener mNegativeButtonListener;
    private OnClickListener mNeutralButtonListener;

    // Listener
    /**
     * キャンセルリスナー
     */
    public interface OnCancelListener {
        /**
         * キャンセルされると呼ばれる
         * 
         * @param df
         */
        void onCancel(AlertDialogFragment df);
    }

    /**
     * キールリスナー
     */
    public interface OnKeyListener {
        /**
         * キーが押されたらと呼ばれる
         * 
         * @param df
         * @param keyCode
         * @param event
         * @return イベント処理があったかどうか
         */
        boolean onKey(AlertDialogFragment df, int keyCode, KeyEvent event);
    }

    /**
     * ボタンクリックリスナー
     */
    public interface OnClickListener {
        /**
         * ダイアログのボタンをクリックすると呼ばれる
         * 
         * @param df
         * @param which
         */
        void onClick(AlertDialogFragment df, int which);
    }

    /**
     * 多重選択リスナー
     */
    public interface OnMultiChoiceClickListener {
        /**
         * 一覧でアイテムを選択すると呼ばれる
         * 
         * @param df
         * @param which
         * @param isChecked
         */
        void onClick(AlertDialogFragment df, int which, boolean isChecked);
    }

    /**
     * FragmentのonCreate()のリスナー
     */
    public interface OnCreateListener {
        /**
         * FragmentのonCreate()直後に呼ばれる
         * 
         * @param savedInstanceState
         */
        void onCreate(Bundle savedInstanceState);
    }

    /**
     * FragmentのonDestroy()のリスナー
     */
    public interface OnDestroyListener {
        /**
         * FragmentのonDestroy()直後に呼ばれる
         */
        void onDestroy();
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Log.d(TAG, "onAttach()" + activity);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate()" + getArguments());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView()" + getArguments());
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Log.d(TAG, "onViewCreated()" + getArguments());
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG, "onActivityCreated()" + getArguments());
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG, "onResume()");
        requestFocus(mRequestFocusId);
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG, "onPause()");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG, "onStop()");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d(TAG, "onDestroyView()");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy()");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(TAG, "onDetach()");
    }

    /**
     * FragmentDialog内のビューを取得する
     * 
     * @param id ビューID
     * @return ビュー
     */
    public View findViewById(int id) {
        if (getDialog() == null) {
            return null;
        }
        return getDialog().findViewById(id);
    }

    /**
     * FragmentDialog内の指定ビューをフォーカス
     * 
     * @param id 指定ビューID
     * @return　フォーカスされたかどうか
     */
    public boolean requestFocus(int id) {
        View target = findViewById(id);
        if (target != null) {
            return target.requestFocus();
        }
        return false;
    }

    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Log.d(TAG, "onCreateDialog()" + getArguments());
        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), mParams.mTheme);

        // OnCancelListener
        mOnCancelListener = mParams.mOnCancelListener;
        DialogInterface.OnCancelListener onCancelListener = null;
        if (mOnCancelListener != null) {
            onCancelListener = new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    mOnCancelListener.onCancel(AlertDialogFragment.this);
                }
            };
        }

        // OnKeyListener
        mOnKeyListener = mParams.mOnKeyListener;
        DialogInterface.OnKeyListener onKeyListener = null;
        if (mOnKeyListener != null) {
            onKeyListener = new DialogInterface.OnKeyListener() {
                @Override
                public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                    return mOnKeyListener.onKey(AlertDialogFragment.this, keyCode, event);
                }
            };
        }

        // OnClickListener
        mOnClickListener = mParams.mOnClickListener;
        DialogInterface.OnClickListener onClickListener = null;
        if (mOnClickListener != null) {
            onClickListener = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    mOnClickListener.onClick(AlertDialogFragment.this, which);
                }
            };
        }
        // onMultiChoiceClickListener
        mOnMultiChoiceClickListener = mParams.mOnMultiChoiceClickListener;
        DialogInterface.OnMultiChoiceClickListener onMultiChoiceClickListener = null;
        if (mOnMultiChoiceClickListener != null) {
            onMultiChoiceClickListener = new DialogInterface.OnMultiChoiceClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                    mOnMultiChoiceClickListener.onClick(AlertDialogFragment.this, which, isChecked);
                }
            };
        }
        // positiveButtonListener
        mPositiveButtonListener = mParams.mPositiveButtonListener;
        DialogInterface.OnClickListener positiveButtonListener = null;
        if (mPositiveButtonListener != null) {
            positiveButtonListener = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    mPositiveButtonListener.onClick(AlertDialogFragment.this, which);
                }
            };
        }
        // negativeButtonListener
        mNegativeButtonListener = mParams.mNegativeButtonListener;
        DialogInterface.OnClickListener negativeButtonListener = null;
        if (mNegativeButtonListener != null) {
            negativeButtonListener = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    mNegativeButtonListener.onClick(AlertDialogFragment.this, which);
                }
            };
        }
        // neutralButtonListener
        mNeutralButtonListener = mParams.mNeutralButtonListener;
        DialogInterface.OnClickListener neutralButtonListener = null;
        if (mNeutralButtonListener != null) {
            neutralButtonListener = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    mNeutralButtonListener.onClick(AlertDialogFragment.this, which);
                }
            };
        }
        //
        mRequestFocusId = mParams.mRequestFocusId;
        setCancelable(mParams.mCancelable);
        builder.setCancelable(mParams.mCancelable);
        builder.setTitle(mParams.mTitle);
        builder.setMessage(mParams.mMessage);
        builder.setIcon(mParams.mIcon);
        builder.setCustomTitle(mParams.mCustomTitleView);
        builder.setIconAttribute(mParams.mAttrId);
        builder.setOnItemSelectedListener(mParams.mOnItemSelectedListener);
        builder.setOnCancelListener(onCancelListener);
        builder.setOnKeyListener(onKeyListener);
        builder.setPositiveButton(mParams.mPositiveButtonText, positiveButtonListener);
        builder.setNegativeButton(mParams.mNegativeButtonText, negativeButtonListener);
        builder.setNeutralButton(mParams.mNeutralButtonText, neutralButtonListener);
        builder.setView(mParams.mView);

        switch (mParams.mType) {
        case Builder.TYPE_ITEMS:
            builder.setItems(mParams.mItems, onClickListener);
            break;
        case Builder.TYPE_ADAPTER:
            builder.setAdapter(mParams.mAdapter, onClickListener);
            break;
        case Builder.TYPE_CURSOR:
            builder.setCursor(mParams.mCursor, onClickListener, mParams.mLabelColumn);
            break;
        case Builder.TYPE_MULTI_CHOICE_ITEMS:
            builder.setMultiChoiceItems(mParams.mItems, mParams.mCheckedItems, onMultiChoiceClickListener);
            break;
        case Builder.TYPE_MULTI_CHOICE_CURSOR:
            builder.setMultiChoiceItems(mParams.mCursor, mParams.mIsCheckedColumn, mParams.mLabelColumn, onMultiChoiceClickListener);
            break;
        case Builder.TYPE_SINGLE_CHOICE_CURSOR:
            builder.setSingleChoiceItems(mParams.mCursor, mParams.mCheckedItem, mParams.mLabelColumn, onClickListener);
            break;
        case Builder.TYPE_SINGLE_CHOICE_ITEMS:
            builder.setSingleChoiceItems(mParams.mItems, mParams.mCheckedItem, onClickListener);
            break;
        case Builder.TYPE_SINGLE_CHOICE_ADAPTER:
            builder.setSingleChoiceItems(mParams.mAdapter, mParams.mCheckedItem, onClickListener);
            break;
        }
        return builder.create();
    }

    // AlertParams
    static class AlertParams {
        Context mContext;
        int mTheme;
        CharSequence mTitle;
        View mCustomTitleView;
        CharSequence mMessage;
        Drawable mIcon;
        int mAttrId;
        CharSequence mPositiveButtonText;
        OnClickListener mPositiveButtonListener;
        CharSequence mNegativeButtonText;
        OnClickListener mNegativeButtonListener;
        CharSequence mNeutralButtonText;
        OnClickListener mNeutralButtonListener;
        boolean mCancelable;
        OnCancelListener mOnCancelListener;
        OnKeyListener mOnKeyListener;
        CharSequence[] mItems;
        OnClickListener mOnClickListener;
        OnMultiChoiceClickListener mOnMultiChoiceClickListener;
        OnItemSelectedListener mOnItemSelectedListener;
        ListAdapter mAdapter;
        Cursor mCursor;
        String mLabelColumn;
        boolean[] mCheckedItems;
        boolean mIsMultiChoice;
        String mIsCheckedColumn;
        boolean mIsSingleChoice;
        int mCheckedItem;
        View mView;
        int mRequestFocusId;
        int mType;
    }

    /**
     * AlertDialgoのBuilder
     */
    public static class Builder {
        static final int TYPE_ITEMS = 1;
        static final int TYPE_ADAPTER = 2;
        static final int TYPE_CURSOR = 3;
        static final int TYPE_MULTI_CHOICE_ITEMS = 4;
        static final int TYPE_MULTI_CHOICE_CURSOR = 5;
        static final int TYPE_SINGLE_CHOICE_CURSOR = 6;
        static final int TYPE_SINGLE_CHOICE_ITEMS = 7;
        static final int TYPE_SINGLE_CHOICE_ADAPTER = 8;

        private AlertDialogFragment mDialog;

        /**
         * コンストラクタ
         * 
         * @param context
         * @param theme
         */
        public Builder(Context context, int theme) {
            mDialog = new AlertDialogFragment();
            mDialog.mParams = new AlertParams();
            mDialog.mParams.mContext = context;
            mDialog.mParams.mTheme = theme;
        }

        /**
         * コンストラクタ
         * 
         * @param context
         */
        public Builder(Context context) {
            this(context, 0);
        }

        /**
         * コンストラクタ
         * 
         * @return Context
         */
        public Context getContext() {
            return mDialog.mParams.mContext;
        }

        /**
         * ダイアログのタイトルを指定する
         * 
         * @param titleId
         * @return Builder
         */
        public AlertDialogFragment.Builder setTitle(int titleId) {
            setTitle(getContext().getText(titleId));
            return this;
        }

        /**
         * ダイアログのタイトルを指定する
         * 
         * @param title
         * @return Builder
         */
        public AlertDialogFragment.Builder setTitle(CharSequence title) {
            mDialog.mParams.mTitle = title;
            return this;
        }

        /**
         * カスタムタイトルを指定する
         * 
         * @param customTitleView
         * @return Builder
         */
        public AlertDialogFragment.Builder setCustomTitle(View customTitleView) {
            mDialog.mParams.mCustomTitleView = customTitleView;
            return this;
        }

        /**
         * ダイアログのメッセージを指定する
         * 
         * @param messageId
         * @return Builder
         */
        public AlertDialogFragment.Builder setMessage(int messageId) {
            setMessage(getContext().getText(messageId));
            return this;
        }

        /**
         * ダイアログのメッセージを指定する
         * 
         * @param message
         * @return Builder
         */
        public AlertDialogFragment.Builder setMessage(CharSequence message) {
            mDialog.mParams.mMessage = message;
            return this;
        }

        /**
         * ダイアログのアイコンを指定する
         * 
         * @param iconId
         * @return Builder
         */
        public AlertDialogFragment.Builder setIcon(int iconId) {
            setIcon(getContext().getResources().getDrawable(iconId));
            return this;
        }

        /**
         * ダイアログのアイコンを指定する
         * 
         * @param icon
         * @return Builder
         */
        public AlertDialogFragment.Builder setIcon(Drawable icon) {
            mDialog.mParams.mIcon = icon;
            return this;
        }

        /**
         * ダイアログのアイコンAttributeを指定する
         * 
         * @param attrId
         * @return Builder
         */
        public AlertDialogFragment.Builder setIconAttribute(int attrId) {
            mDialog.mParams.mAttrId = attrId;
            return this;
        }

        /**
         * ダイアログのPositiveボタンを指定する
         * 
         * @param textId
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setPositiveButton(int textId, OnClickListener listener) {
            setPositiveButton(getContext().getText(textId), listener);
            return this;
        }

        /**
         * ダイアログのPositiveボタンを指定する
         * 
         * @param text
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setPositiveButton(CharSequence text, OnClickListener listener) {
            mDialog.mParams.mPositiveButtonText = text;
            mDialog.mParams.mPositiveButtonListener = listener;
            return this;
        }

        /**
         * ダイアログのNegativeボタンを指定する
         * 
         * @param textId
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setNegativeButton(int textId, OnClickListener listener) {
            setNegativeButton(getContext().getText(textId), listener);
            return this;
        }

        /**
         * ダイアログのNegativeボタンを指定する
         * 
         * @param text
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setNegativeButton(CharSequence text, OnClickListener listener) {
            mDialog.mParams.mNegativeButtonText = text;
            mDialog.mParams.mNegativeButtonListener = listener;
            return this;
        }

        /**
         * ダイアログのNeutralボタンを指定する
         * 
         * @param textId
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setNeutralButton(int textId, OnClickListener listener) {
            setNeutralButton(getContext().getText(textId), listener);
            return this;
        }

        /**
         * ダイアログのNeutralボタンを指定する
         * 
         * @param text
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setNeutralButton(CharSequence text, OnClickListener listener) {
            mDialog.mParams.mNeutralButtonText = text;
            mDialog.mParams.mNeutralButtonListener = listener;
            return this;
        }

        /**
         * ダイアログのキャンセル可否を指定する
         * 
         * @param cancelable
         * @return Builder
         */
        public AlertDialogFragment.Builder setCancelable(boolean cancelable) {
            mDialog.mParams.mCancelable = cancelable;
            return this;
        }

        /**
         * ダイアログのキャンセルリスナーを指定する
         * 
         * @param onCancelListener
         * @return Builder
         */
        public AlertDialogFragment.Builder setOnCancelListener(OnCancelListener onCancelListener) {
            mDialog.mParams.mOnCancelListener = onCancelListener;
            return this;
        }

        /**
         * ダイアログのキーリスナーを指定する
         * 
         * @param onKeyListener
         * @return Builder
         */
        public AlertDialogFragment.Builder setOnKeyListener(OnKeyListener onKeyListener) {
            mDialog.mParams.mOnKeyListener = onKeyListener;
            return this;
        }

        /**
         * ダイアログ一覧のデータを指定する
         * 
         * @param itemsId
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setItems(int itemsId, OnClickListener listener) {
            setItems(getContext().getResources().getTextArray(itemsId), listener);
            return this;
        }

        /**
         * ダイアログ 一覧のデータを指定する
         * 
         * @param items
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setItems(CharSequence[] items, OnClickListener listener) {
            mDialog.mParams.mType = TYPE_ITEMS;
            mDialog.mParams.mItems = items;
            mDialog.mParams.mOnClickListener = listener;
            return this;
        }

        /**
         * ダイアログ一覧のデータを指定する
         * 
         * @param adapter
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setAdapter(ListAdapter adapter, OnClickListener listener) {
            mDialog.mParams.mType = TYPE_ADAPTER;
            mDialog.mParams.mAdapter = adapter;
            mDialog.mParams.mOnClickListener = listener;
            return this;
        }

        /**
         * ダイアログ一覧のデータを指定する
         * 
         * @param cursor
         * @param listener
         * @param labelColumn
         * @return Builder
         */
        public AlertDialogFragment.Builder setCursor(Cursor cursor, OnClickListener listener, String labelColumn) {
            mDialog.mParams.mType = TYPE_CURSOR;
            mDialog.mParams.mCursor = cursor;
            mDialog.mParams.mOnClickListener = listener;
            mDialog.mParams.mLabelColumn = labelColumn;
            return this;
        }

        /**
         * ダイアログ一覧のデータを指定する
         * 
         * @param itemsId
         * @param checkedItems
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setMultiChoiceItems(int itemsId, boolean[] checkedItems, OnMultiChoiceClickListener listener) {
            setMultiChoiceItems(getContext().getResources().getTextArray(itemsId), checkedItems, listener);
            return this;
        }

        /**
         * ダイアログ一覧のデータを指定する
         * 
         * @param items
         * @param checkedItems
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, OnMultiChoiceClickListener listener) {
            mDialog.mParams.mType = TYPE_MULTI_CHOICE_ITEMS;
            mDialog.mParams.mItems = items;
            mDialog.mParams.mCheckedItems = checkedItems;
            mDialog.mParams.mOnMultiChoiceClickListener = listener;
            return this;
        }

        /**
         * 一覧のデータを指定する
         * 
         * @param cursor
         * @param isCheckedColumn
         * @param labelColumn
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, OnMultiChoiceClickListener listener) {
            mDialog.mParams.mType = TYPE_MULTI_CHOICE_CURSOR;
            mDialog.mParams.mCursor = cursor;
            mDialog.mParams.mIsCheckedColumn = isCheckedColumn;
            mDialog.mParams.mLabelColumn = labelColumn;
            mDialog.mParams.mOnMultiChoiceClickListener = listener;
            return this;
        }

        /**
         * 一覧のデータを指定する
         * 
         * @param itemsId
         * @param checkedItem
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setSingleChoiceItems(int itemsId, int checkedItem, OnClickListener listener) {
            setSingleChoiceItems(getContext().getResources().getTextArray(itemsId), checkedItem, listener);
            return this;
        }

        /**
         * ダイアログ一覧のデータを指定する
         * 
         * @param cursor
         * @param checkedItem
         * @param labelColumn
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, OnClickListener listener) {
            mDialog.mParams.mType = TYPE_SINGLE_CHOICE_CURSOR;
            mDialog.mParams.mCursor = cursor;
            mDialog.mParams.mCheckedItem = checkedItem;
            mDialog.mParams.mLabelColumn = labelColumn;
            mDialog.mParams.mOnClickListener = listener;
            return this;
        }

        /**
         * ダイアログ一覧のデータを指定する
         * 
         * @param items
         * @param checkedItem
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, OnClickListener listener) {
            mDialog.mParams.mType = TYPE_SINGLE_CHOICE_ITEMS;
            mDialog.mParams.mItems = items;
            mDialog.mParams.mCheckedItem = checkedItem;
            mDialog.mParams.mOnClickListener = listener;
            return this;
        }

        /**
         * ダイアログ 一覧のデータを指定する
         * 
         * @param adapter
         * @param checkedItem
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setSingleChoiceItems(ListAdapter adapter, int checkedItem, OnClickListener listener) {
            mDialog.mParams.mType = TYPE_SINGLE_CHOICE_ADAPTER;
            mDialog.mParams.mAdapter = adapter;
            mDialog.mParams.mCheckedItem = checkedItem;
            mDialog.mParams.mOnClickListener = listener;
            return this;
        }

        /**
         * 一覧のOnItemSelectedListenerを指定する
         * 
         * @param listener
         * @return Builder
         */
        public AlertDialogFragment.Builder setOnItemSelectedListener(OnItemSelectedListener listener) {
            mDialog.mParams.mOnItemSelectedListener = listener;
            return this;
        }

        /**
         * ダイアログにカスタムビューを設定する
         * 
         * @param view
         * @return Builder
         */
        public AlertDialogFragment.Builder setView(View view) {
            mDialog.mParams.mView = view;
            return this;
        }

        /**
         * フォーカスを指定する
         * 
         * @param resId
         * @return Builder
         */
        public AlertDialogFragment.Builder requestFocus(int resId) {
            mDialog.mParams.mRequestFocusId = resId;
            return this;
        }

        /**
         * ダイアログを表示する
         * 
         * @param manager
         * @param tag
         */
        public void show(FragmentManager manager, String tag) {
            show(manager, null, tag);
        }

        /**
         * ダイアログを表示する
         * 
         * @param manager
         * @param args
         * @param tag
         */
        public void show(FragmentManager manager, Bundle args, String tag) {
            mDialog.setArguments(args);
            mDialog.show(manager, tag);
        }

        /**
         * ダイアログを作成する
         * 
         * @return ダイアログ
         */
        public DialogFragment build() {
            return mDialog;
        }
    }

}
